package cz.proks.bank.manager;

import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.activation.DataHandler;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cz.proks.bank.client.FileServiceClient;
import cz.proks.bank.domain.Account;
import cz.proks.bank.domain.OperationLog;
import cz.proks.bank.domain.OperationLog.OperationType;
import cz.proks.bank.manager.exeception.ReportException;
import cz.proks.bank.service.fileservice.AccountRecord;
import cz.proks.bank.service.fileservice.Report;
import cz.proks.bank.service.fileservice.ReportRequest;

@Service
public class ReportManager {
	@Autowired
	private FileServiceClient fileClient;
	
	public DataHandler generateReport(Account account, List<OperationLog> operationLogs) throws ReportException{		
		try {
			ReportRequest reportRequest = toReportRequest(account, operationLogs);
		
			Report report = fileClient.generateAccountReport(reportRequest);
			DataHandler dataHandler = report.getReport();
		
			return dataHandler;
		} catch (cz.proks.bank.service.fileservice.ReportException_Exception e) {
			throw new ReportException(e);
		}
	}
	
	private ReportRequest toReportRequest(Account account, List<OperationLog> operationLogs) throws ReportException {
		if (account == null)
			throw new ReportException("No account!");
				

		ReportRequest reportRequest = new ReportRequest();
		
		reportRequest.setAccountNumber(account.getId());
		reportRequest.setBankCode(account.getBank().getCode());
		
		for (OperationLog operationLog : operationLogs) {
			AccountRecord accountRecord = new AccountRecord();
			
			accountRecord.setOperationType(toRequestOperationType(operationLog.getType()));
			accountRecord.setAdditionalInformation(operationLog.getAdditionalInfo());
			accountRecord.setDate(toXmlCalendar(operationLog.getDate()));
			
			reportRequest.getRecords().add(accountRecord);
		}		
		
		return reportRequest;
	}
	
	private cz.proks.bank.service.fileservice.OperationType toRequestOperationType(OperationType operationType) {
		switch (operationType) {
			case INGOING_PAYMENT: 
				return cz.proks.bank.service.fileservice.OperationType.INGOING_PAYMENT;
			
			case OUTGOING_PAYMENT:
				return cz.proks.bank.service.fileservice.OperationType.OUTGOING_PAYMENT;
				
			case MONEY_DEPOSIT:
				return cz.proks.bank.service.fileservice.OperationType.MONEY_DEPOSIT;
				
			case MONEY_WITHDRAW:
				return cz.proks.bank.service.fileservice.OperationType.MONEY_WITHDRAW;
				
			case NEW_ACCOUNT:
				return cz.proks.bank.service.fileservice.OperationType.NEW_ACCOUNT;	
				
			case LOAN_REPAYMENT:
				return cz.proks.bank.service.fileservice.OperationType.LOAN_REPAYMENT;
				
			case NEW_LOAN:
				return cz.proks.bank.service.fileservice.OperationType.NEW_LOAN;
				
			default:
				throw new IllegalArgumentException();
		}	
	}
	
	private XMLGregorianCalendar toXmlCalendar(Date date) {
		if (date == null)
			return null;
		
		try {
			GregorianCalendar calendar = new GregorianCalendar();
			calendar.setTime(date);
			XMLGregorianCalendar xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar);
			
			return xmlCalendar;
		} catch (DatatypeConfigurationException e) {
			return null;
		}
	}
}
